home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection 1998 Fall: Game Toolkit / Disc.iso / Samples / SprocketExamples / GlyphaIV / GlyphaIV Sources / G4Graphics.c < prev    next >
Encoding:
Text File  |  1998-07-14  |  46.6 KB  |  1,532 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        G4Graphics.c
  3.  
  4.     Contains:    xxx put contents here xxx
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.     Copyright:    © 1998 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     File Ownership:
  11.  
  12.         DRI:                xxx put dri here xxx
  13.  
  14.         Other Contact:        xxx put other contact here xxx
  15.  
  16.         Technology:            xxx put technology here xxx
  17.  
  18.     Writers:
  19.  
  20.         (sjb)    Steve Bollinger
  21.  
  22.     Change History (most recent first):
  23.  
  24.          <3>      7/1/98    sjb        Update to CWPro 2
  25. */
  26.  
  27.  
  28. //============================================================================
  29. //----------------------------------------------------------------------------
  30. //                                    Graphics.c
  31. //----------------------------------------------------------------------------
  32. //============================================================================
  33.  
  34. // I like to isolate all the graphic routines - put them in their own file.
  35. // This way all the thousands of Rect variables and Pixmaps have a place to go.
  36. // Anyway, this file contains all the drawing routines.
  37.  
  38. #include "G4Externs.h"
  39. #include <Palettes.h>
  40. #include <QuickdrawText.h>
  41. #include <Fonts.h>
  42. #include <TextUtils.h>
  43. #include <Events.h>
  44.  
  45. #define kUpperEyeHeight            100
  46. #define kLowerEyeHeight            200
  47. #define kNumLightningPts        8
  48.  
  49.  
  50. void QuickUnionRect (Rect *, Rect *, Rect *);
  51. void CheckPlayerWrapAround (void);
  52. void DrawHand (void);
  53. void DrawEye (void);
  54. void DrawPlayer (void);
  55. void CheckEnemyWrapAround (short);
  56. void DrawEnemies (void);
  57. void DrawBanner (void);
  58. void DrawLava(void);
  59.  
  60. void HandleLava(void);
  61. void HandlePixelShatter(void);
  62.  
  63. Rect        backSrcRect, workSrcRect, obSrcRect, playerSrcRect;
  64. Rect        numberSrcRect, idleSrcRect, enemyWalkSrcRect, enemyFlySrcRect;
  65. Rect        obeliskRects[4], playerRects[11], numbersSrc[11], numbersDest[11];
  66. Rect        flameSrcRect, flameDestRects[2], flameRects[4], eggSrcRect;
  67. Rect        platformSrcRect, platformCopyRects[9], helpSrcRect, eyeSrcRect, bannerSrcRect;
  68. Rect        helpSrc, helpDest, handSrcRect, handRects[2], eyeRects[4];
  69. Point        leftLightningPts[kNumLightningPts], rightLightningPts[kNumLightningPts];
  70. CGrafPtr    origBackSrcMap, backSrcMap, workSrcMap, obeliskSrcMap, playerSrcMap, eyeSrcMap;
  71. CGrafPtr    numberSrcMap, idleSrcMap, enemyWalkSrcMap, enemyFlySrcMap;
  72. CGrafPtr    flameSrcMap, eggSrcMap, bannerSrcMap, platformSrcMap, helpSrcMap, handSrcMap;
  73. GrafPtr        playerMaskMap, enemyWalkMaskMap, enemyFlyMaskMap, eggMaskMap;
  74. GrafPtr        handMaskMap, eyeMaskMap, obeliskMaskMap;
  75. Boolean        whichList, helpOpen, scoresOpen;
  76.  
  77. short numPixelShatter;
  78. pixelShatter thePixelShatter[kMaxPixelShatter];
  79.  
  80. extern    handInfo    theHand;
  81. extern    eyeInfo        theEye;
  82. extern    prefsInfo    thePrefs;
  83. extern    playerType    thePlayer;
  84. extern    enemyType    theEnemies[];
  85. extern    Rect        enemyRects[24];
  86. extern    long        theScore, wasTensOfThousands;
  87. extern    short        livesLeft, levelOn, numEnemies;
  88. extern    Boolean        evenFrame;
  89.  
  90. extern short lightningCount;
  91. void HandleLightning();
  92.  
  93.  
  94. extern short oldFrameRate;
  95.  
  96. // in DR3 of DrawSprocket the underlay buffer will give the game the
  97. // ability to not worry about keeping track fo the update rects.  As it
  98. // is right now, if you use update rects you have to save the update
  99. // rectangle for each frame, and the number of frames will vary depending
  100. // on the state of triple buffering and page flipping.
  101. // 
  102. // Once the Underlay buffers are operational, enabiling this #define
  103. // will allow DS to optimize the screen updates instead of doing
  104. // a full screen copy (as happens in Glypha)
  105. //#define USE_INVALID_RECTS 1
  106.  
  107. //==============================================================  Functions
  108. //--------------------------------------------------------------  DrawPlatforms
  109.  
  110. // This function draws all the platforms on the background pixmap and the…
  111. // work pixmap.  It needs to know merely how many of them to draw.
  112.  
  113. void DrawPlatforms (short howMany)
  114. {
  115.     if (howMany > 3)            // If there are more than 3 platforms…
  116.     {                            // Draw a platform to background pixmap.
  117.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  118.                 &((GrafPtr)backSrcMap)->portBits, 
  119.                 &platformCopyRects[2], &platformCopyRects[7], srcCopy, 0L);
  120.         
  121.                                 // Draw a platform to work pixmap.
  122.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  123.                 &((GrafPtr)workSrcMap)->portBits, 
  124.                 &platformCopyRects[7], &platformCopyRects[7], srcCopy, 0L);
  125.         #ifdef USE_INVALID_RECTS
  126.         DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[7] );
  127.         #endif
  128.  
  129.                                 // Add rectangle to update list to be drawn to screen.
  130.                                 // Ditto for a second platform.
  131.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  132.                 &((GrafPtr)backSrcMap)->portBits, 
  133.                 &platformCopyRects[4], &platformCopyRects[8], srcCopy, 0L);
  134.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  135.                 &((GrafPtr)workSrcMap)->portBits, 
  136.                 &platformCopyRects[8], &platformCopyRects[8], srcCopy, 0L);
  137.         #ifdef USE_INVALID_RECTS
  138.         DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[8] );
  139.         #endif
  140.  
  141.     }
  142.     else                        // If there are 3 or less platforms…
  143.     {
  144.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  145.                 &((GrafPtr)backSrcMap)->portBits, 
  146.                 &platformCopyRects[3], &platformCopyRects[7], srcCopy, 0L);
  147.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  148.                 &((GrafPtr)workSrcMap)->portBits, 
  149.                 &platformCopyRects[7], &platformCopyRects[7], srcCopy, 0L);
  150.         #ifdef USE_INVALID_RECTS
  151.         DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[7] );
  152.         #endif
  153.  
  154.         
  155.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  156.                 &((GrafPtr)backSrcMap)->portBits, 
  157.                 &platformCopyRects[5], &platformCopyRects[8], srcCopy, 0L);
  158.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  159.                 &((GrafPtr)workSrcMap)->portBits, 
  160.                 &platformCopyRects[8], &platformCopyRects[8], srcCopy, 0L);
  161.         #ifdef USE_INVALID_RECTS
  162.         DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[8] );
  163.         #endif
  164.  
  165.     }
  166.     
  167.     if (howMany > 5)        // If there are more than 5 platforms…
  168.     {
  169.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  170.                 &((GrafPtr)backSrcMap)->portBits, 
  171.                 &platformCopyRects[0], &platformCopyRects[6], srcCopy, 0L);
  172.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  173.                 &((GrafPtr)workSrcMap)->portBits, 
  174.                 &platformCopyRects[6], &platformCopyRects[6], srcCopy, 0L);
  175.         #ifdef USE_INVALID_RECTS
  176.         DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[6] );
  177.         #endif
  178.  
  179.     }
  180.     else                    // If there are 5 or less platforms…
  181.     {
  182.         CopyBits(&((GrafPtr)platformSrcMap)->portBits, 
  183.                 &((GrafPtr)backSrcMap)->portBits, 
  184.                 &platformCopyRects[1], &platformCopyRects[6], srcCopy, 0L);
  185.         CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  186.                 &((GrafPtr)workSrcMap)->portBits, 
  187.                 &platformCopyRects[6], &platformCopyRects[6], srcCopy, 0L);
  188.         #ifdef USE_INVALID_RECTS
  189.         DSpContext_InvalBackBufferRect( gTheContext, &platformCopyRects[6] );
  190.         #endif
  191.  
  192.     }
  193. }
  194.  
  195. //--------------------------------------------------------------  ScrollHelp
  196.  
  197. // This function scrolls the help screen.  You pass it a number of pixels…
  198. // to scroll up or down (positive or negative number).
  199.  
  200. void ScrollHelp (short scrollDown)
  201. {
  202.     // don't do any drawing, drawing is done by the idle animation automatically
  203.     
  204.     OffsetRect(&helpSrc, 0, scrollDown);        // Move the source rectangle.
  205.     
  206.     if (helpSrc.bottom > 398)                    // Check to see we don't go too far.
  207.     {
  208.         helpSrc.bottom = 398;
  209.         helpSrc.top = helpSrc.bottom - 199;
  210.     }
  211.     else if (helpSrc.top < 0)
  212.     {
  213.         helpSrc.top = 0;
  214.         helpSrc.bottom = helpSrc.top + 199;
  215.     }
  216. }
  217.  
  218. //--------------------------------------------------------------  OpenHelp
  219.  
  220. // Bring up the help screen.  This is a kind of "wipe" or "barn door" effect.
  221.  
  222. void OpenHelp (void)
  223. {
  224.     Rect        wallSrc, wallDest;
  225.     short        i;
  226.     
  227.     SetRect(&helpSrc, 0, 0, 231, 0);    // Initialize source and destination rects.
  228.     helpDest = helpSrc;
  229.     OffsetRect(&helpDest, 204, 171);
  230.     
  231.     SetRect(&wallSrc, 0, 0, 231, 199);
  232.     OffsetRect(&wallSrc, 204, 171);
  233.     wallDest = wallSrc;
  234.     
  235.     for (i = 0; i < 199; i ++)            // Loop through 1 pixel at a time.
  236.     {
  237.         DSpContext_GetBackBuffer( gTheContext, kDSpBufferKind_Normal, &workSrcMap );
  238.  
  239.         DumpBackToWorkMap();                    // clear the screen
  240.         HandleLava();
  241.         HandlePixelShatter();
  242.         DrawTorches();
  243.         DrawBanner();
  244.         DrawLava();
  245.         DrawPixelShatter();
  246.  
  247.         LogNextTick(1L);                // Speed governor.
  248.         helpSrc.bottom++;                // Grow help source rect.
  249.         helpDest.bottom++;                // Grow help dest as well.
  250.         wallSrc.bottom--;                // Shrink wall source.
  251.         wallDest.top++;                    // Shrink wall dest.
  252.         
  253.                                         // So, as the help graphic grows, the wall graphic…
  254.                                         // shrinks.  Thus it is as though the wall is…
  255.                                         // lifting up to expose the help screen beneath.
  256.         
  257.         CopyBits(    &((GrafPtr)helpSrcMap)->portBits, 
  258.                     &((GrafPtr)workSrcMap)->portBits, 
  259.                     &helpSrc, &helpDest, srcCopy, 0L);
  260.         #ifdef USE_INVALID_RECTS
  261.         DSpContext_InvalBackBufferRect( gTheContext, &helpDest );
  262.         #endif
  263.  
  264.  
  265.         CopyBits(    &((GrafPtr)backSrcMap)->portBits, 
  266.                     &((GrafPtr)workSrcMap)->portBits, 
  267.                     &wallSrc, &wallDest, srcCopy, 0L);
  268.         #ifdef USE_INVALID_RECTS
  269.         DSpContext_InvalBackBufferRect( gTheContext, &wallDest );
  270.         #endif
  271.  
  272.                                         // Copy slightly larger help screen.
  273.  
  274.         DSpContext_SwapBuffers( gTheContext, NULL, NULL );
  275.     }
  276.     helpOpen = TRUE;                    // When done, set flag to indicate help is open.
  277. }
  278.  
  279. //--------------------------------------------------------------  CloseWall
  280.  
  281. // Close the wall over whatever screen is up (help screen or high scores).
  282. // Since the wall just comes down over the opening - covering whatever was beneath,…
  283. // it's simpler than the above function.
  284.  
  285. void CloseWall (void)
  286. {
  287.     DSpContext_GetBackBuffer( gTheContext, kDSpBufferKind_Normal, &workSrcMap );
  288.     DumpBackToWorkMap();                    // clear the screen
  289.     DSpContext_SwapBuffers( gTheContext, NULL, NULL );
  290. }
  291.  
  292. //--------------------------------------------------------------  OpenHighScores
  293.  
  294. // This function is practically identical to the OpenHelp().  The only real…
  295. // difference is that we must first draw all the high scores offscreen before…
  296. // lifting the wall to reveal them.
  297.  
  298. void OpenHighScores (void)
  299. {
  300.     RGBColor    theRGBColor, wasColor;
  301.     Rect        wallSrc, wallDest;
  302.     Rect        scoreSrc, scoreDest;
  303.     Str255        scoreStr;
  304.     short        i, scoreWide;
  305.     
  306.     SetRect(&scoreSrc, 0, 0, 231, 0);                // Initialize source and dest rects.
  307.     OffsetRect(&scoreSrc, 204, 171);
  308.     scoreDest = scoreSrc;
  309.     
  310.     SetRect(&wallSrc, 0, 0, 231, 199);
  311.     OffsetRect(&wallSrc, 204, 171);
  312.     wallDest = wallSrc;
  313.     
  314.     SetPort((GrafPtr)workSrcMap);                    // We'll draw scores to the work pixmap.
  315.     PaintRect(&wallSrc);                            // Paint it black.
  316.     
  317.     GetForeColor(&wasColor);                        // Save the foreground color.
  318.     
  319.     TextFont(kFontIDGeneva);                        // Use Geneva 12 point Bold font.
  320.     TextSize(12);
  321.     TextFace(bold);
  322.     
  323.     Index2Color(132, &theRGBColor);                    // Get the 132nd color in RGB form.
  324.     RGBForeColor(&theRGBColor);                        // Make this color the pen color.
  325.     MoveTo(scoreSrc.left + 36, scoreSrc.top + 20);    // Get pen in right position to draw.
  326.     DrawString("\pGlypha IV High Scores");            // Draw the title.
  327.     
  328.     TextFont(kFontIDGeneva);                        // Use Geneva 9 point Bold font.
  329.     TextSize(9);
  330.     TextFace(bold);
  331.     
  332.     for (i = 0; i < 10; i++)                        // Walk through all 10 high scores.
  333.     {
  334.         Index2Color(133, &theRGBColor);                // Use color 133 (in palette).
  335.         RGBForeColor(&theRGBColor);
  336.         NumToString((long)i + 1L, scoreStr);        // Draw "place" (1, 2, 3, …).
  337.         MoveTo(scoreSrc.left + 8, scoreSrc.top + 40 + (i * 16));
  338.         DrawString(scoreStr);
  339.         
  340.         Index2Color(128, &theRGBColor);                // Use color 128 (from palette).
  341.         RGBForeColor(&theRGBColor);
  342.         MoveTo(scoreSrc.left + 32, scoreSrc.top + 40 + (i * 16));
  343.         DrawString(thePrefs.highNames[i]);            // Draw the high score name (Sue, …).
  344.         
  345.         Index2Color(164, &theRGBColor);                // Use color 164 (from palette).
  346.         RGBForeColor(&theRGBColor);
  347.         NumToString(thePrefs.highScores[i], scoreStr);
  348.         scoreWide = StringWidth(scoreStr);            // Right justify.
  349.         MoveTo(scoreSrc.left + 191 - scoreWide, scoreSrc.top + 40 + (i * 16));
  350.         DrawString(scoreStr);                        // Draw the high score (12,000, …).
  351.         
  352.         Index2Color(134, &theRGBColor);                // Use color 134 (from palette).
  353.         RGBForeColor(&theRGBColor);
  354.         NumToString(thePrefs.highLevel[i], scoreStr);
  355.         scoreWide = StringWidth(scoreStr);            // Right justify.
  356.         MoveTo(scoreSrc.left + 223 - scoreWide, scoreSrc.top + 40 + (i * 16));
  357.         DrawString(scoreStr);                        // Draw highest level (12, 10, …).
  358.     }
  359.     
  360.     RGBForeColor(&wasColor);                        // Restore foreground color.
  361.  
  362.     for (i = 0; i < 199; i ++)                        // Now the standard scroll functions.
  363.     {
  364.         WaitForNextTick();
  365.         
  366.         DSpContext_GetBackBuffer( gTheContext, kDSpBufferKind_Normal, &workSrcMap );
  367.         DumpBackToWorkMap();                    // clear the screen
  368.     
  369.         LogNextTick(1L);                // Speed governor.
  370.         scoreSrc.bottom++;
  371.         scoreDest.bottom++;
  372.         wallSrc.bottom--;
  373.         wallDest.top++;
  374.         
  375.                                         // So, as the help graphic grows, the wall graphic…
  376.                                         // shrinks.  Thus it is as though the wall is…
  377.                                         // lifting up to expose the help screen beneath.
  378.         
  379.         CopyBits(    &((GrafPtr)workSrcMap)->portBits, 
  380.                     &((GrafPtr)workSrcMap)->portBits, 
  381.                     &scoreSrc, &scoreDest, srcCopy, 0L);
  382.         #ifdef USE_INVALID_RECTS
  383.         DSpContext_InvalBackBufferRect( gTheContext, &scoreDest );
  384.         #endif
  385.  
  386.  
  387.         CopyBits(    &((GrafPtr)backSrcMap)->portBits, 
  388.                     &((GrafPtr)workSrcMap)->portBits, 
  389.                     &wallSrc, &wallDest, srcCopy, 0L);
  390.         #ifdef USE_INVALID_RECTS
  391.         DSpContext_InvalBackBufferRect( gTheContext, &wallDest );
  392.         #endif
  393.  
  394.                                         // Copy slightly larger help screen.
  395.  
  396.         DSpContext_SwapBuffers( gTheContext, NULL, NULL );
  397.     }
  398.     
  399.     scoresOpen = TRUE;                                // Flag that the scores are up.
  400. }
  401.  
  402. //--------------------------------------------------------------  UpdateLivesNumbers
  403.  
  404. // During a game, this function is called to reflect the current number of lives.
  405. // This is "lives remaining", so 1 is subtracted before displaying it to the screen.
  406. // The lives is "wrapped around" after 99.  So 112 lives will display as 12.  It's…
  407. // a lot easier to handle numbers this way (it beats a recursive function that might…
  408. // potentially draw across the entire screen.
  409.  
  410. void UpdateLivesNumbers (void)
  411. {
  412.     short        digit;
  413.     
  414.     digit = (livesLeft - 1) / 10;        // Get the "10's" digit.
  415.     digit = digit % 10L;                // Keep it less than 10 (0 -> 9).
  416.     if ((digit == 0) && ((livesLeft - 1) < 10))
  417.         digit = 10;                        // Use a "blank" space if zero and less than 10.
  418.                                         // Draw digit.
  419.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  420.             &((GrafPtr)backSrcMap)->portBits, 
  421.             &numbersSrc[digit], &numbersDest[0], srcCopy, 0L);
  422.     #ifdef USE_INVALID_RECTS
  423.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[0] );
  424.     #endif
  425.  
  426.  
  427.     digit = (livesLeft - 1) % 10;        // Get 1's digit.
  428.                                         // Draw digit.
  429.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  430.             &((GrafPtr)backSrcMap)->portBits, 
  431.             &numbersSrc[digit], &numbersDest[1], srcCopy, 0L);
  432.     #ifdef USE_INVALID_RECTS
  433.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[1] );
  434.     #endif
  435.  
  436. }
  437.  
  438. //--------------------------------------------------------------  UpdateScoreNumbers
  439.  
  440. // This function works just like the above function.  However, we allow the…
  441. // score to go to 6 digits (999,999) before rolling over.  Note however, that…
  442. // in both the case of the score, number of lives, etc., the game does in fact…
  443. // keep track of the "actual" number.  It is just that only so many digits are…
  444. // being displayed.
  445.  
  446. void UpdateScoreNumbers (void)
  447. {
  448.     long        digit;
  449.  
  450.     digit = theScore / 100000L;        // Get "hundreds of thousands" digit
  451.     digit = digit % 10L;            // Clip off anything greater than 9.
  452.     if ((digit == 0) && (theScore < 1000000L))
  453.         digit = 10;                    // Use blank space if zero.
  454.                                     // Draw digit.
  455.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  456.             &((GrafPtr)backSrcMap)->portBits, 
  457.             &numbersSrc[digit], &numbersDest[2], srcCopy, 0L);
  458.     #ifdef USE_INVALID_RECTS
  459.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[2] );
  460.     #endif
  461.  
  462.  
  463.     digit = theScore / 10000L;        // Get "tens of thousands" digit.
  464.     if (digit > wasTensOfThousands)    // Check for "extra life" here.
  465.     {
  466.         livesLeft++;                // Increment number of lives.
  467.         UpdateLivesNumbers();        // Reflect new lives on screen.
  468.         wasTensOfThousands = digit;    // Note that life was given.
  469.     }
  470.     digit = digit % 10L;            // Clip off anything greater than 9.
  471.     if ((digit == 0) && (theScore < 100000L))
  472.         digit = 10;                    // Use blank space if zero.
  473.                                     // Draw digit.
  474.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  475.             &((GrafPtr)backSrcMap)->portBits, 
  476.             &numbersSrc[digit], &numbersDest[3], srcCopy, 0L);
  477.     #ifdef USE_INVALID_RECTS
  478.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[3] );
  479.     #endif
  480.  
  481.     
  482.     digit = theScore / 1000L;        // Handle "thousands" digit.
  483.     digit = digit % 10L;
  484.     if ((digit == 0) && (theScore < 10000L))
  485.         digit = 10;
  486.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  487.             &((GrafPtr)backSrcMap)->portBits, 
  488.             &numbersSrc[digit], &numbersDest[4], srcCopy, 0L);
  489.     #ifdef USE_INVALID_RECTS
  490.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[4] );
  491.     #endif
  492.  
  493.  
  494.     digit = theScore / 100L;        // Handle 100's digit.
  495.     digit = digit % 10L;
  496.     if ((digit == 0) && (theScore < 1000L))
  497.         digit = 10;
  498.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  499.             &((GrafPtr)backSrcMap)->portBits, 
  500.             &numbersSrc[digit], &numbersDest[5], srcCopy, 0L);
  501.     #ifdef USE_INVALID_RECTS
  502.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[5] );
  503.     #endif
  504.  
  505.  
  506.     digit = theScore / 10L;            // Handle 10's digit.
  507.     digit = digit % 10L;
  508.     if ((digit == 0) && (theScore < 100L))
  509.         digit = 10;
  510.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  511.             &((GrafPtr)backSrcMap)->portBits, 
  512.             &numbersSrc[digit], &numbersDest[6], srcCopy, 0L);
  513.     #ifdef USE_INVALID_RECTS
  514.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[6] );
  515.     #endif
  516.  
  517.     
  518.     digit = theScore % 10L;            // Handle 1's digit.
  519.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  520.             &((GrafPtr)backSrcMap)->portBits, 
  521.             &numbersSrc[digit], &numbersDest[7], srcCopy, 0L);
  522.     #ifdef USE_INVALID_RECTS
  523.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[7] );
  524.     #endif
  525. }
  526.  
  527. //--------------------------------------------------------------  UpdateLevelNumbers
  528.  
  529. // Blah, blah, blah.  Just like the above functions but handles displaying the…
  530. // level the player is on.  We allow 3 digits here (up to 999) before wrapping.
  531.  
  532. void UpdateLevelNumbers (void)
  533. {
  534.     short        digit;
  535.     short        workNumber;
  536.     
  537. //    workNumber = levelOn;
  538.     workNumber = oldFrameRate;
  539.         
  540.     digit = (workNumber + 1) / 100;        // Do 100's digit.
  541.     digit = digit % 10L;
  542.     if ((digit == 0) && ((workNumber + 1) < 1000))
  543.         digit = 10;
  544.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  545.             &((GrafPtr)backSrcMap)->portBits, 
  546.             &numbersSrc[digit], &numbersDest[8], srcCopy, 0L);
  547.     #ifdef USE_INVALID_RECTS
  548.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[3] );
  549.     #endif
  550.     
  551.     digit = (workNumber + 1) / 10;            // Do 10's digit.
  552.     digit = digit % 10L;
  553.     if ((digit == 0) && ((workNumber + 1) < 100))
  554.         digit = 10;
  555.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  556.             &((GrafPtr)backSrcMap)->portBits, 
  557.             &numbersSrc[digit], &numbersDest[9], srcCopy, 0L);
  558.     #ifdef USE_INVALID_RECTS
  559.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[9] );
  560.     #endif
  561.     
  562.     digit = (workNumber + 1) % 10;            // Do 1's digit.
  563.     CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  564.             &((GrafPtr)backSrcMap)->portBits, 
  565.             &numbersSrc[digit], &numbersDest[10], srcCopy, 0L);
  566.     #ifdef USE_INVALID_RECTS
  567.     DSpContext_InvalBackBufferRect( gTheContext, &numbersDest[10] );
  568.     #endif
  569. }
  570.  
  571. //--------------------------------------------------------------  GenerateLightning
  572.  
  573. // This function takes a point (h and v) and then generates two lightning bolts…
  574. // (one from the tip of each obelisk) to the point.  It does this by generating…
  575. // a list of segments (as the lightning is broken up into segements).  The drawing…
  576. // counterpart to this function will draw a line connecting these segements (a sort…
  577. // of dot-to-dot).
  578.  
  579. void GenerateLightning (short h, short v)
  580. {
  581.     #define kLeftObeliskH        172
  582.     #define kLeftObeliskV        250
  583.     #define kRightObeliskH        468
  584.     #define kRightObeliskV        250
  585.     #define kWander                16
  586.     
  587.     short        i, leftDeltaH, rightDeltaH, leftDeltaV, rightDeltaV, range;
  588.     
  589.     leftDeltaH = h - kLeftObeliskH;                // Determine the h and v distances between…
  590.     rightDeltaH = h - kRightObeliskH;            // obelisks and the target point.
  591.     leftDeltaV = v - kLeftObeliskV;
  592.     rightDeltaV = v - kRightObeliskV;
  593.     
  594.     for (i = 0; i < kNumLightningPts; i++)        // Calculate an even spread of points between…
  595.     {                                            // obelisk tips and the target point.
  596.         leftLightningPts[i].h = (leftDeltaH * i) / (kNumLightningPts - 1) + kLeftObeliskH;
  597.         leftLightningPts[i].v = (leftDeltaV * i) / (kNumLightningPts - 1) + kLeftObeliskV;
  598.         rightLightningPts[i].h = (rightDeltaH * i) / (kNumLightningPts - 1) + kRightObeliskH;
  599.         rightLightningPts[i].v = (rightDeltaV * i) / (kNumLightningPts - 1) + kRightObeliskV;
  600.     }
  601.     
  602.     range = kWander * 2 + 1;                    // Randomly scatter the points vertically…
  603.     for (i = 1; i < kNumLightningPts - 1; i++)    // but NOT the 1st or last points.
  604.     {
  605.         leftLightningPts[i].v += RandomInt(range) - kWander;
  606.         rightLightningPts[i].v += RandomInt(range) - kWander;
  607.     }
  608. }
  609.  
  610. void DrawObelisks (void)
  611. {    
  612.     if ((lightningCount > 0) && evenFrame)        // Draw them "inverted"
  613.     {
  614.         CopyMask(    &((GrafPtr)obeliskSrcMap)->portBits,        // src
  615.                     &((GrafPtr)obeliskMaskMap)->portBits,        // mask
  616.                     &((GrafPtr) workSrcMap)->portBits,             // dst
  617.                     &obeliskRects[0],                             // src rect
  618.                     &obeliskRects[0],                             // mask rect
  619.                     &obeliskRects[2]);                            // dst rect
  620.         #ifdef USE_INVALID_RECTS
  621.         DSpContext_InvalBackBufferRect( gTheContext, &obeliskRects[2] );
  622.         #endif
  623.  
  624.         CopyMask(    &((GrafPtr)obeliskSrcMap)->portBits,        // src
  625.                     &((GrafPtr)obeliskMaskMap)->portBits,        // mask
  626.                     &((GrafPtr) workSrcMap)->portBits,             // dst
  627.                     &obeliskRects[1],                             // src rect
  628.                     &obeliskRects[1],                             // mask rect
  629.                     &obeliskRects[3]);                            // dst rect
  630.         #ifdef USE_INVALID_RECTS
  631.         DSpContext_InvalBackBufferRect( gTheContext, &obeliskRects[3] );
  632.         #endif
  633.     }
  634.     else
  635.     {
  636.         CopyMask(    &((GrafPtr)backSrcMap)->portBits,        // src
  637.                     &((GrafPtr)obeliskMaskMap)->portBits,        // mask
  638.                     &((GrafPtr) workSrcMap)->portBits,             // dst
  639.                     &obeliskRects[2],                             // src rect
  640.                     &obeliskRects[0],                             // mask rect
  641.                     &obeliskRects[2]);                             // dst rect
  642.         #ifdef USE_INVALID_RECTS
  643.         DSpContext_InvalBackBufferRect( gTheContext, &obeliskRects[2] );
  644.         #endif
  645.  
  646.         CopyMask(    &((GrafPtr)backSrcMap)->portBits,        // src
  647.                     &((GrafPtr)obeliskMaskMap)->portBits,        // mask
  648.                     &((GrafPtr) workSrcMap)->portBits,             // dst
  649.                     &obeliskRects[3],                             // src rect
  650.                     &obeliskRects[1],                             // mask rect
  651.                     &obeliskRects[3]);                            // dst rect
  652.         #ifdef USE_INVALID_RECTS
  653.         DSpContext_InvalBackBufferRect( gTheContext, &obeliskRects[3] );
  654.         #endif
  655.     }
  656. }
  657.  
  658.  
  659. void StrikeLightningWork (void)
  660. {
  661.     short        i;
  662.     GrafPtr        oldPort;
  663.     RGBColor     yellow = {65535, 65535, 0};
  664.     Rect        theRect;
  665.     
  666.     GetPort(&oldPort);
  667.     SetPort((GrafPtr)workSrcMap);
  668.     PenSize(1, 2);                                // Use a tall pen.
  669.     RGBForeColor(&yellow);
  670.                                                 // Draw lightning bolts with inverted pen.
  671.     MoveTo(leftLightningPts[0].h, leftLightningPts[0].v);
  672.     for (i = 0; i < kNumLightningPts - 1; i++)    // Draw left lightning bolt.
  673.     {
  674.         MoveTo(leftLightningPts[i].h, leftLightningPts[i].v);
  675.         LineTo(leftLightningPts[i + 1].h - 1, leftLightningPts[i + 1].v);
  676.     }
  677.     SetRect( &theRect, leftLightningPts[0].h, leftLightningPts[0].v, 
  678.         leftLightningPts[kNumLightningPts].h - 1, leftLightningPts[kNumLightningPts].v );
  679.     #ifdef USE_INVALID_RECTS
  680.     DSpContext_InvalBackBufferRect( gTheContext, &theRect );
  681.     #endif
  682.     
  683.     MoveTo(rightLightningPts[0].h, rightLightningPts[0].v);
  684.     for (i = 0; i < kNumLightningPts - 1; i++)    // Draw right lightning bolt.
  685.     {
  686.         MoveTo(rightLightningPts[i].h, rightLightningPts[i].v);
  687.         LineTo(rightLightningPts[i + 1].h - 1, rightLightningPts[i + 1].v);
  688.     }
  689.     SetRect( &theRect, rightLightningPts[0].h, rightLightningPts[0].v, 
  690.         rightLightningPts[kNumLightningPts].h - 1, rightLightningPts[kNumLightningPts].v );
  691.     #ifdef USE_INVALID_RECTS
  692.     DSpContext_InvalBackBufferRect( gTheContext, &theRect );
  693.     #endif
  694.     
  695.     PenNormal();                                // Return pen to normal.
  696.     
  697.     SetPort(oldPort);
  698. }
  699.  
  700. //--------------------------------------------------------------  DumpBackToWorkMap
  701.  
  702. // Simple handy function that copies the entire background pixmap to the…
  703. // work pixmap.
  704. //--
  705.  
  706. //--------------------------------------------------------------  DumpBackToWorkMap
  707.  
  708. // Simple handy function that copies the entire background pixmap to the…
  709. // work pixmap.
  710.  
  711.  
  712. static inline void ClassicDumpBackToWork(void)
  713. {
  714.     // this is doing a full clean of the work map from the source map, don't inval
  715.     // this rect.
  716.     //
  717.     // • this will go away once DrawSprocket Underlays are used (in DR3 release)
  718.     CopyBits(&((GrafPtr)backSrcMap)->portBits, 
  719.             &((GrafPtr)workSrcMap)->portBits, 
  720.             &backSrcRect, &backSrcRect, srcCopy, 0L);
  721. }
  722.  
  723. // faster on some machines, on others it is slow because of dcbz
  724. static inline void FastDumpBackToWorkMap (void)
  725. {
  726.     CGrafPtr srcGrafPtr = backSrcMap;
  727.     PixMap *srcMap = *(srcGrafPtr->portPixMap);
  728.     char *src = srcMap->baseAddr;
  729.     UInt32 srcBump = srcMap->rowBytes & 0x3fff;
  730.     
  731.     CGrafPtr dstGrafPtr = workSrcMap;
  732.     PixMap *dstMap = *(dstGrafPtr->portPixMap);
  733.     char *dst = dstMap->baseAddr;
  734.     UInt32 dstBump = dstMap->rowBytes & 0x3fff;
  735.     
  736.     int count;
  737.     
  738.     for(count = 0; count < 480; count++)
  739.     {
  740.         BlockMoveData(src,dst,640);
  741.         
  742.         src += srcBump;
  743.         dst += dstBump;
  744.     }
  745. }
  746.  
  747. void DumpBackToWorkMap(void)
  748. {    
  749.     ClassicDumpBackToWork();
  750. }
  751.  
  752. //--------------------------------------------------------------  QuickUnionRect
  753.  
  754. // The Mac Toolbox gives you a UnionRect() function, but, like any Toolbox…
  755. // routine, if we can do it faster, we ought to.  Well, the function below…
  756. // is quick because (among other reasons), it assumes that the two rects…
  757. // being compared are the same size.
  758. //
  759. // Notes from Cary Farrier: Sorry John I don't agree with that advice.  You
  760. // may be able to do something faster, but the speed gain you achieve may not
  761. // be worth the effort required to develop, test, and debug the code.  John's
  762. // advice is good for some scenarios, but it is the exception and not the
  763. // rule.
  764. void QuickUnionRect (Rect *rect1, Rect *rect2, Rect *whole)
  765. {
  766.     if (rect1->left < rect2->left)        // See if we're to use rect1's left.
  767.     {
  768.         whole->left = rect1->left;
  769.         whole->right = rect2->right;
  770.     }
  771.     else                                // Use rect2's left.
  772.     {
  773.         whole->left = rect2->left;
  774.         whole->right = rect1->right;
  775.     }
  776.     
  777.     if (rect1->top < rect2->top)        // See if we're to use rect1's top.
  778.     {
  779.         whole->top = rect1->top;
  780.         whole->bottom = rect2->bottom;
  781.     }
  782.     else                                // Use rect2's top.
  783.     {
  784.         whole->top = rect2->top;
  785.         whole->bottom = rect1->bottom;
  786.     }
  787. }
  788.  
  789. //--------------------------------------------------------------  CheckPlayerWrapAround
  790.  
  791. // This handles drawing wrap-around.  It is such that, when a player walks partly…
  792. // off the right edge of the screen, you see the player peeking through on the left…
  793. // side of the screen.  Since we can't (shouldn't) assume that the physical screen…
  794. // memory wraps around, we'll draw the right player clipped against the right edge…
  795. // of the screen and draw a SECOND PLAYER on the left edge (clipped to the left).
  796.  
  797. void CheckPlayerWrapAround (void)
  798. {
  799.     Rect        wrapRect, wasWrapRect, src;
  800.     
  801.     if (thePlayer.dest.right > 640)        // Player off right edge of screen.
  802.     {
  803.         thePlayer.wrapping = TRUE;        // Set "wrapping" flag.
  804.         wrapRect = thePlayer.dest;        // Start out with copy of player bounds.
  805.         wrapRect.left -= 640;            // Offset it a screenwidth to left.
  806.         wrapRect.right -= 640;
  807.                                         // Ditto with old location.
  808.         wasWrapRect = thePlayer.wasDest;
  809.         wasWrapRect.left -= 640;
  810.         wasWrapRect.right -= 640;
  811.         
  812.         if (thePlayer.mode == kBones)    // Draw second bones.
  813.         {
  814.             src = playerRects[thePlayer.srcNum];
  815.             src.bottom = src.top + thePlayer.frame;
  816.             CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  817.                     &((GrafPtr)playerMaskMap)->portBits, 
  818.                     &((GrafPtr)workSrcMap)->portBits, 
  819.                     &src, &src, &wrapRect);
  820.             #ifdef USE_INVALID_RECTS
  821.             DSpContext_InvalBackBufferRect( gTheContext, &wrapRect );
  822.             #endif
  823.         }
  824.         else                            // Draw second player (not bones).
  825.         {
  826.             CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  827.                     &((GrafPtr)playerMaskMap)->portBits, 
  828.                     &((GrafPtr)workSrcMap)->portBits, 
  829.                     &playerRects[thePlayer.srcNum], 
  830.                     &playerRects[thePlayer.srcNum], 
  831.                     &wrapRect);
  832.             #ifdef USE_INVALID_RECTS
  833.             DSpContext_InvalBackBufferRect( gTheContext, &wrapRect );
  834.             #endif
  835.         }
  836.         thePlayer.wrap = wrapRect;
  837.     }
  838.     else if (thePlayer.dest.left < 0)    // Else if off the left edge…
  839.     {
  840.         thePlayer.wrapping = TRUE;        // Set "wrapping" flag.
  841.         wrapRect = thePlayer.dest;        // Start out with copy of player bounds.
  842.         wrapRect.left += 640;            // Offset it a screenwidth to right.
  843.         wrapRect.right += 640;
  844.                                         // Ditto with old location.
  845.         wasWrapRect = thePlayer.wasDest;
  846.         wasWrapRect.left += 640;
  847.         wasWrapRect.right += 640;
  848.         
  849.         if (thePlayer.mode == kBones)    // Draw second bones.
  850.         {
  851.             src = playerRects[thePlayer.srcNum];
  852.             src.bottom = src.top + thePlayer.frame;
  853.             CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  854.                     &((GrafPtr)playerMaskMap)->portBits, 
  855.                     &((GrafPtr)workSrcMap)->portBits, 
  856.                     &src, &src, &wrapRect);
  857.             #ifdef USE_INVALID_RECTS
  858.             DSpContext_InvalBackBufferRect( gTheContext, &wrapRect );
  859.             #endif
  860.         }
  861.         else                            // Draw second player (not bones).
  862.         {
  863.             CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  864.                     &((GrafPtr)playerMaskMap)->portBits, 
  865.                     &((GrafPtr)workSrcMap)->portBits, 
  866.                     &playerRects[thePlayer.srcNum], 
  867.                     &playerRects[thePlayer.srcNum], 
  868.                     &wrapRect);
  869.             #ifdef USE_INVALID_RECTS
  870.             DSpContext_InvalBackBufferRect( gTheContext, &wrapRect );
  871.             #endif
  872.         }
  873.         thePlayer.wrap = wrapRect;
  874.     }
  875.     else
  876.         thePlayer.wrapping = FALSE;        // Otherwise, we're not wrapping.
  877. }
  878.  
  879. //--------------------------------------------------------------  DrawTorches
  880.  
  881. // This handles drawing the two torch's flames.  It chooses randomly from…
  882. // 4 torch graphics and draws right over the old torches.
  883.  
  884. void DrawTorches (void)
  885. {
  886.     short        who;
  887.     
  888.     who = RandomInt(4);
  889.     if (evenFrame)        // Only draw 1 torch - left on even frames…
  890.     {
  891.         CopyBits(&((GrafPtr)flameSrcMap)->portBits, 
  892.                 &((GrafPtr)workSrcMap)->portBits, 
  893.                 &flameRects[who], &flameDestRects[0], srcCopy, 0L);
  894.         #ifdef USE_INVALID_RECTS
  895.         DSpContext_InvalBackBufferRect( gTheContext, &flameDestRects[0] );
  896.         #endif
  897.     }
  898.     else                // and draw the right torch on odd frames.
  899.     {                    // We do this even/odd thing for speed.  Why draw both?
  900.         CopyBits(&((GrafPtr)flameSrcMap)->portBits, 
  901.                 &((GrafPtr)workSrcMap)->portBits, 
  902.                 &flameRects[who], &flameDestRects[1], srcCopy, 0L);
  903.         #ifdef USE_INVALID_RECTS
  904.         DSpContext_InvalBackBufferRect( gTheContext, &flameDestRects[1] );
  905.         #endif
  906.     }
  907. }
  908.  
  909. //--------------------------------------------------------------  DrawHand
  910.  
  911. // This function takes care of drawing the hand offscreen.  There are only…
  912. // two (well really three) choices - hand open, hand clutching (or no hand…
  913. // in which case both options are skipped).
  914.  
  915. void DrawHand (void)
  916. {
  917.     theHand.dest.right = theHand.dest.left + 56;
  918.     theHand.dest.bottom = theHand.dest.top + 57;
  919.  
  920.     if (theHand.mode == kOutGrabeth)        // Fingers open.
  921.     {
  922.         CopyMask(&((GrafPtr)handSrcMap)->portBits, 
  923.                 &((GrafPtr)handMaskMap)->portBits, 
  924.                 &((GrafPtr)workSrcMap)->portBits, 
  925.                 &handRects[0], 
  926.                 &handRects[0], 
  927.                 &theHand.dest);
  928.         #ifdef USE_INVALID_RECTS
  929.         DSpContext_InvalBackBufferRect( gTheContext, &theHand.dest );
  930.         #endif
  931.     }
  932.     else if (theHand.mode == kClutching)    // Fingers clenched.
  933.     {
  934.         CopyMask(&((GrafPtr)handSrcMap)->portBits, 
  935.                 &((GrafPtr)handMaskMap)->portBits, 
  936.                 &((GrafPtr)workSrcMap)->portBits, 
  937.                 &handRects[1], 
  938.                 &handRects[1], 
  939.                 &theHand.dest);
  940.         #ifdef USE_INVALID_RECTS
  941.         DSpContext_InvalBackBufferRect( gTheContext, &theHand.dest );
  942.         #endif
  943.     }
  944. }
  945.  
  946. //--------------------------------------------------------------  DrawEye
  947.  
  948. // This function draws the eye (if it's floating about - stalking).
  949.  
  950. void DrawEye (void)
  951. {
  952.     if (theEye.mode == kStalking)
  953.     {
  954.         CopyMask(&((GrafPtr)eyeSrcMap)->portBits, 
  955.                 &((GrafPtr)eyeMaskMap)->portBits, 
  956.                 &((GrafPtr)workSrcMap)->portBits, 
  957.                 &eyeRects[theEye.srcNum], 
  958.                 &eyeRects[theEye.srcNum], 
  959.                 &theEye.dest);
  960.         #ifdef USE_INVALID_RECTS
  961.         DSpContext_InvalBackBufferRect( gTheContext, &theEye.dest );
  962.         #endif
  963.     }
  964. }
  965.  
  966. //--------------------------------------------------------------  DrawPlayer
  967.  
  968. // Although called "DrawPlayer()", this function actually does its drawing…
  969. // offscreen.  It is the above routine that will finally copy our offscreen…
  970. // work to the main screen.  Anyway, the below function draws the player…
  971. // offscreen in the correct position and state.
  972.  
  973. void DrawPlayer (void)
  974. {
  975.     Rect        src;
  976.     
  977.     if ((evenFrame) && (thePlayer.mode == kIdle))
  978.     {            // On even frames, we'll draw the "flashed" graphic of the player.
  979.                 // If you've played Glypha, you notice that the player begins a…
  980.                 // game flashing alternately between bones and a normal player.
  981.         CopyMask(&((GrafPtr)idleSrcMap)->portBits, 
  982.                 &((GrafPtr)playerMaskMap)->portBits, 
  983.                 &((GrafPtr)workSrcMap)->portBits, 
  984.                 &idleSrcRect, 
  985.                 &playerRects[thePlayer.srcNum], 
  986.                 &thePlayer.dest);
  987.         #ifdef USE_INVALID_RECTS
  988.         DSpContext_InvalBackBufferRect( gTheContext, &thePlayer.dest );
  989.         #endif
  990.     }
  991.     else if (thePlayer.mode == kBones)
  992.     {            // If the player is dead and a pile of bones…
  993.         src = playerRects[thePlayer.srcNum];
  994.         src.bottom = src.top + thePlayer.frame;
  995.         CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  996.                 &((GrafPtr)playerMaskMap)->portBits, 
  997.                 &((GrafPtr)workSrcMap)->portBits, 
  998.                 &src, &src, &thePlayer.dest);
  999.         #ifdef USE_INVALID_RECTS
  1000.         DSpContext_InvalBackBufferRect( gTheContext, &thePlayer.dest );
  1001.         #endif
  1002.     }
  1003.     else        // Else, if the player is neither idle nor dead…
  1004.     {
  1005.         CopyMask(&((GrafPtr)playerSrcMap)->portBits, 
  1006.                 &((GrafPtr)playerMaskMap)->portBits, 
  1007.                 &((GrafPtr)workSrcMap)->portBits, 
  1008.                 &playerRects[thePlayer.srcNum], 
  1009.                 &playerRects[thePlayer.srcNum], 
  1010.                 &thePlayer.dest);
  1011.         #ifdef USE_INVALID_RECTS
  1012.         DSpContext_InvalBackBufferRect( gTheContext, &thePlayer.dest );
  1013.         #endif
  1014.     }
  1015.                 // Now we add the player to the update rect list.
  1016.                 // Record old locations.
  1017.     thePlayer.wasH = thePlayer.h;
  1018.     thePlayer.wasV = thePlayer.v;
  1019.                 // Record old bounds rect.
  1020.     thePlayer.wasDest = thePlayer.dest;
  1021. }
  1022.  
  1023. //--------------------------------------------------------------  CheckEnemyWrapAround
  1024.  
  1025. // This function both determines whether or not an enemy (sphinx) is wrapping around.
  1026. // If it is, the "second" wrapped-around enemy is drawn.
  1027.  
  1028. void CheckEnemyWrapAround (short who)
  1029. {
  1030.     Rect        wrapRect, wasWrapRect, src;
  1031.     
  1032.     if (theEnemies[who].dest.right > 640)    // Is enemy off the right edge of screen?
  1033.     {
  1034.         wrapRect = theEnemies[who].dest;    // Copy bounds.
  1035.         wrapRect.left -= 640;                // Offset bounds copy to left (one screen width).
  1036.         wrapRect.right -= 640;
  1037.                                             // Ditto with old bounds.
  1038.         wasWrapRect = theEnemies[who].wasDest;
  1039.         wasWrapRect.left -= 640;
  1040.         wasWrapRect.right -= 640;
  1041.                                             // Handle "egg" enemies.
  1042.         if ((theEnemies[who].mode == kFalling) || (theEnemies[who].mode == kEggTimer))
  1043.         {                                    // Handle "egg" enemy sinking into platform.
  1044.             if ((theEnemies[who].mode == kEggTimer) && (theEnemies[who].frame < 24))
  1045.             {
  1046.                 src = eggSrcRect;
  1047.                 src.bottom = src.top + theEnemies[who].frame;
  1048.             }
  1049.             else
  1050.                 src = eggSrcRect;
  1051.             CopyMask(&((GrafPtr)eggSrcMap)->portBits, 
  1052.                     &((GrafPtr)eggMaskMap)->portBits, 
  1053.                     &((GrafPtr)workSrcMap)->portBits, 
  1054.                     &src, &src, &wrapRect);
  1055.             #ifdef USE_INVALID_RECTS
  1056.             DSpContext_InvalBackBufferRect( gTheContext, &wrapRect );
  1057.             #endif
  1058.         }
  1059.         else                                // Otherwise, if enemy not an egg…
  1060.         {
  1061.             CopyMask(&((GrafPtr)enemyFlySrcMap)->portBits, 
  1062.                     &((GrafPtr)enemyFlyMaskMap)->portBits, 
  1063.                     &((GrafPtr)workSrcMap)->portBits, 
  1064.                     &enemyRects[theEnemies[who].srcNum], 
  1065.                     &enemyRects[theEnemies[who].srcNum], 
  1066.                     &wrapRect);
  1067.             #ifdef USE_INVALID_RECTS
  1068.             DSpContext_InvalBackBufferRect( gTheContext, &wrapRect );
  1069.             #endif
  1070.         }
  1071.     }
  1072.     else if (theEnemies[who].dest.left < 0)    // Check to see if enemy off left edge instead.
  1073.     {
  1074.         wrapRect = theEnemies[who].dest;    // Make a copy of enemy bounds.
  1075.         wrapRect.left += 640;                // Offset it right one screens width.
  1076.         wrapRect.right += 640;
  1077.                                             // Ditto with old bounds.
  1078.         wasWrapRect = theEnemies[who].wasDest;
  1079.         wasWrapRect.left += 640;
  1080.         wasWrapRect.right += 640;
  1081.         if ((theEnemies[who].mode == kFalling) || (theEnemies[who].mode == kEggTimer))
  1082.         {                                    // Blah, blah, blah.  This is just like the above.
  1083.             if ((theEnemies[who].mode == kEggTimer) && (theEnemies[who].frame < 24))
  1084.             {
  1085.                 src = eggSrcRect;
  1086.                 src.bottom = src.top + theEnemies[who].frame;
  1087.             }
  1088.             else
  1089.                 src = eggSrcRect;
  1090.             CopyMask(&((GrafPtr)eggSrcMap)->portBits, 
  1091.                     &((GrafPtr)eggMaskMap)->portBits, 
  1092.                     &((GrafPtr)workSrcMap)->portBits, 
  1093.                     &src, &src, &wrapRect);
  1094.             #ifdef USE_INVALID_RECTS
  1095.             DSpContext_InvalBackBufferRect( gTheContext, &wrapRect );
  1096.             #endif
  1097.         }
  1098.         else
  1099.         {
  1100.             CopyMask(&((GrafPtr)enemyFlySrcMap)->portBits, 
  1101.                     &((GrafPtr)enemyFlyMaskMap)->portBits, 
  1102.                     &((GrafPtr)workSrcMap)->portBits, 
  1103.                     &enemyRects[theEnemies[who].srcNum], 
  1104.                     &enemyRects[theEnemies[who].srcNum], 
  1105.                     &wrapRect);
  1106.             #ifdef USE_INVALID_RECTS
  1107.             DSpContext_InvalBackBufferRect( gTheContext, &wrapRect );
  1108.             #endif
  1109.         }
  1110.     }
  1111. }
  1112.  
  1113. //--------------------------------------------------------------  DrawEnemies
  1114.  
  1115. // This function draws all the sphinx enemies (or eggs if they're in that state).
  1116. // It doesn't handle wrap-around (the above function does) but it does call it.
  1117.  
  1118. void DrawEnemies (void)
  1119. {
  1120.     Rect        src;
  1121.     short        i;
  1122.     
  1123.     for (i = 0; i < numEnemies; i++)    // Go through all enemies.
  1124.     {
  1125.         switch (theEnemies[i].mode)        // Handle the different modes as seperate cases.
  1126.         {
  1127.             case kSpawning:                // Spawning enemies are "growing" out of the platform.
  1128.             src = enemyRects[theEnemies[i].srcNum];
  1129.             src.bottom = src.top + theEnemies[i].frame;
  1130.             CopyMask(&((GrafPtr)enemyWalkSrcMap)->portBits, 
  1131.                     &((GrafPtr)enemyWalkMaskMap)->portBits, 
  1132.                     &((GrafPtr)workSrcMap)->portBits, 
  1133.                     &src, &src, &theEnemies[i].dest);
  1134.             #ifdef USE_INVALID_RECTS
  1135.             DSpContext_InvalBackBufferRect( gTheContext, &theEnemies[i].dest );
  1136.             #endif
  1137.                     
  1138.                                         // Don't need to check wrap-around, when enemies…
  1139.                                         // spawn, they're never on the edge of screen.
  1140.             theEnemies[i].wasDest = theEnemies[i].dest;
  1141.             theEnemies[i].wasH = theEnemies[i].h;
  1142.             theEnemies[i].wasV = theEnemies[i].v;
  1143.             break;
  1144.             
  1145.             case kFlying:                // Flying enemies are air borne (gee).
  1146.             CopyMask(&((GrafPtr)enemyFlySrcMap)->portBits, 
  1147.                     &((GrafPtr)enemyFlyMaskMap)->portBits, 
  1148.                     &((GrafPtr)workSrcMap)->portBits, 
  1149.                     &enemyRects[theEnemies[i].srcNum], &enemyRects[theEnemies[i].srcNum], 
  1150.                     &theEnemies[i].dest);
  1151.             #ifdef USE_INVALID_RECTS
  1152.             DSpContext_InvalBackBufferRect( gTheContext, &theEnemies[i].dest );
  1153.             #endif
  1154.                     
  1155.             CheckEnemyWrapAround(i);    // I like the word "air bourne".
  1156.             theEnemies[i].wasDest = theEnemies[i].dest;
  1157.             theEnemies[i].wasH = theEnemies[i].h;
  1158.             theEnemies[i].wasV = theEnemies[i].v;
  1159.             break;
  1160.             
  1161.             case kWalking:                // Walking enemies are walking.  Enemies.
  1162.             CopyMask(&((GrafPtr)enemyWalkSrcMap)->portBits, 
  1163.                     &((GrafPtr)enemyWalkMaskMap)->portBits, 
  1164.                     &((GrafPtr)workSrcMap)->portBits, 
  1165.                     &enemyRects[theEnemies[i].srcNum], &enemyRects[theEnemies[i].srcNum], 
  1166.                     &theEnemies[i].dest);
  1167.             #ifdef USE_INVALID_RECTS
  1168.             DSpContext_InvalBackBufferRect( gTheContext, &theEnemies[i].dest );
  1169.             #endif
  1170.                                         // Don't need to check wrap-around, enemies walk…
  1171.                                         // only briefly, and never off edge of screen.
  1172.             theEnemies[i].wasDest = theEnemies[i].dest;
  1173.             theEnemies[i].wasH = theEnemies[i].h;
  1174.             theEnemies[i].wasV = theEnemies[i].v;
  1175.             break;
  1176.             
  1177.             case kFalling:                // Falling enemies are in fact eggs!
  1178.             CopyMask(&((GrafPtr)eggSrcMap)->portBits, 
  1179.                     &((GrafPtr)eggMaskMap)->portBits, 
  1180.                     &((GrafPtr)workSrcMap)->portBits, 
  1181.                     &eggSrcRect, &eggSrcRect, &theEnemies[i].dest);
  1182.             #ifdef USE_INVALID_RECTS
  1183.             DSpContext_InvalBackBufferRect( gTheContext, &theEnemies[i].dest );
  1184.             #endif
  1185.                     
  1186.             CheckEnemyWrapAround(i);    // Check for wrap around.
  1187.             theEnemies[i].wasDest = theEnemies[i].dest;
  1188.             theEnemies[i].wasH = theEnemies[i].h;
  1189.             theEnemies[i].wasV = theEnemies[i].v;
  1190.             break;
  1191.             
  1192.             case kEggTimer:                // These are idle, perhaps hatching, eggs.
  1193.             if (theEnemies[i].frame < 24)
  1194.             {                            // Below countdown = 24, the egss are sinking…
  1195.                 src = eggSrcRect;        // into the platform (hatch time!).
  1196.                 src.bottom = src.top + theEnemies[i].frame;
  1197.             }
  1198.             else
  1199.                 src = eggSrcRect;
  1200.             CopyMask(&((GrafPtr)eggSrcMap)->portBits, 
  1201.                     &((GrafPtr)eggMaskMap)->portBits, 
  1202.                     &((GrafPtr)workSrcMap)->portBits, 
  1203.                     &src, &src, &theEnemies[i].dest);
  1204.             #ifdef USE_INVALID_RECTS
  1205.             DSpContext_InvalBackBufferRect( gTheContext, &theEnemies[i].dest );
  1206.             #endif
  1207.                     
  1208.             CheckEnemyWrapAround(i);    // Check for wrap around.
  1209.             theEnemies[i].wasDest = theEnemies[i].dest;
  1210.             theEnemies[i].wasH = theEnemies[i].h;
  1211.             theEnemies[i].wasV = theEnemies[i].v;
  1212.             break;
  1213.         }
  1214.     }
  1215. }
  1216.  
  1217. //------------- DrawBanner
  1218. void DrawBanner (void)
  1219. {
  1220.     Rect destRect;
  1221.     Rect srcRect;
  1222.     long start = (TickCount() / 2) % 1280;
  1223.     long seg1Len;
  1224.     long seg2Len;
  1225.     
  1226.     if (start <= 640) 
  1227.     {
  1228.         seg1Len = 640;
  1229.         seg2Len = 0;
  1230.     }
  1231.     else
  1232.     {
  1233.         seg1Len = 1280 - start;
  1234.         seg2Len = 640 - seg1Len;
  1235.     }
  1236.     
  1237.     SetRect(&destRect,
  1238.             0,        // left
  1239.             460,    // top
  1240.             seg1Len,    // right
  1241.             480);    // bottom
  1242.     
  1243.             
  1244.     SetRect(&srcRect,
  1245.             start,
  1246.             0,
  1247.             start + seg1Len,
  1248.             20);
  1249.             
  1250.             
  1251.     CopyBits(    &((GrafPtr)bannerSrcMap)->portBits, 
  1252.                 &((GrafPtr)workSrcMap)->portBits, 
  1253.                 &srcRect, &destRect, srcCopy, 0L);
  1254.     #ifdef USE_INVALID_RECTS
  1255.     DSpContext_InvalBackBufferRect( gTheContext, &destRect );
  1256.     #endif
  1257.                 
  1258.     if (seg2Len > 0)
  1259.     {
  1260.         destRect.left = seg1Len;
  1261.         destRect.right = 640;
  1262.         srcRect.left = 0;
  1263.         srcRect.right = seg2Len;
  1264.         
  1265.         CopyBits(    &((GrafPtr)bannerSrcMap)->portBits, 
  1266.                     &((GrafPtr)workSrcMap)->portBits, 
  1267.                     &srcRect, &destRect, srcCopy, 0L);
  1268.     #ifdef USE_INVALID_RECTS
  1269.     DSpContext_InvalBackBufferRect( gTheContext, &destRect );
  1270.     #endif
  1271.     }
  1272.  
  1273. }
  1274.  
  1275. //--------------------------------------------------------------  DrawPixelShatter
  1276.  
  1277. void DrawPixelShatter (void)
  1278. {
  1279.     int i;
  1280.     CGrafPtr theGrafPtr = workSrcMap;
  1281.     PixMap *theMap = *(theGrafPtr->portPixMap);
  1282.     short h,v;
  1283.     short rowBytes = theMap->rowBytes & 0x3fff;
  1284.     short minH = 1000, minV = 1000, maxH = 0, maxV = 0;
  1285.     Rect theRect;
  1286.     
  1287.     for(i = 0; i < numPixelShatter; i++)
  1288.     {
  1289.         char *addr = theMap->baseAddr;
  1290.         int offset = 0;
  1291.                 
  1292.         h = thePixelShatter[i].h;
  1293.         v = thePixelShatter[i].v;
  1294.         if( h < minH )
  1295.             minH = h;
  1296.         if( h > maxH )
  1297.             maxH = h;
  1298.         if( v < minV )
  1299.             minV = v;
  1300.         if( v > maxV )
  1301.             maxV = v;
  1302.             
  1303.         h >>= 4;
  1304.         v >>= 4;
  1305.         
  1306.         offset = rowBytes * v;
  1307.         offset += h;
  1308.         
  1309.         addr += offset;
  1310.         
  1311.         *addr = thePixelShatter[i].color;
  1312.     }
  1313.     
  1314.     SetRect( &theRect, minH, minV, maxH, maxV );
  1315.     #ifdef USE_INVALID_RECTS
  1316.     DSpContext_InvalBackBufferRect( gTheContext, &theRect );
  1317.     #endif
  1318.     
  1319. }
  1320.  
  1321. //--------------------------------------------------------------  DrawLava
  1322. void DrawLava(void);
  1323. #if 0
  1324. void DrawLava(void)
  1325. {
  1326.     short where = RandomInt(640);
  1327.     short velocity = -(RandomInt(15) + 15);
  1328.  
  1329.     StartPixelShatter(    where, 460, 0, velocity, kShatterLavaBubble);
  1330. }
  1331. #endif
  1332.  
  1333. void DrawScoreFloaters(void);
  1334. void DrawScoreFloaters(void)
  1335. {
  1336. #if 0
  1337.     int i,j,count;
  1338.     Rect r;
  1339.     CGrafPtr theGrafPtr = workSrcMap;
  1340.     PixMap *theMap = *(theGrafPtr->portPixMap);
  1341.     short rowBytes = theMap->rowBytes & 0x3fff;
  1342.     char *addr = theMap->baseAddr;
  1343.     
  1344.     for(count = 0; count < numScoreFloater; count++)
  1345.     {
  1346.         r.top = theScoreFloater[count].location.v;
  1347.         r.left = theScoreFloater[count].location.h;
  1348.         r.bottom = theScoreFloater[count].location.v + 20;
  1349.         r.right = theScoreFloater[count].location.h + 60;
  1350.     
  1351.         addr = theMap->baseAddr + (r.top * rowBytes);
  1352.         
  1353.         for(j = r.top; j < r.bottom; j++)
  1354.         {
  1355.             for(i = r.left; i < r.right; i++)
  1356.             {
  1357.                 addr[i] = 0;
  1358.             }
  1359.             
  1360.             addr += rowBytes;
  1361.         }
  1362.     }
  1363. #else
  1364.     int count;
  1365.     Rect baseRect = {0,0,8,11};
  1366.         
  1367.     for(count = 0; count < numScoreFloater; count++)
  1368.     {
  1369.         short        digit;
  1370.         short        workNumber;
  1371.         Rect r = baseRect;
  1372.                 
  1373.         r.top += theScoreFloater[count].location.v;
  1374.         r.bottom += theScoreFloater[count].location.v;
  1375.         r.left += theScoreFloater[count].location.h;
  1376.         r.right += theScoreFloater[count].location.h;
  1377.         workNumber = theScoreFloater[count].score;
  1378.             
  1379.         digit = (workNumber + 1) / 1000;        // Do 1000's digit.
  1380.         digit = digit % 10L;
  1381.         if (digit != 0)
  1382.         {
  1383.             CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  1384.                     &((GrafPtr)workSrcMap)->portBits, 
  1385.                     &numbersSrc[digit], &r, srcCopy, 0L);
  1386.             #ifdef USE_INVALID_RECTS
  1387.             DSpContext_InvalBackBufferRect( gTheContext, &r );
  1388.             #endif
  1389.         }
  1390.         
  1391.         r.left += 11;
  1392.         r.right += 11;
  1393.  
  1394.         digit = (workNumber + 1) / 100;        // Do 100's digit.
  1395.         digit = digit % 10L;
  1396.         if ((digit != 0) || (workNumber >= 1000))
  1397.         {
  1398.             CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  1399.                     &((GrafPtr)workSrcMap)->portBits, 
  1400.                     &numbersSrc[digit], &r, srcCopy, 0L);
  1401.             #ifdef USE_INVALID_RECTS
  1402.             DSpContext_InvalBackBufferRect( gTheContext, &r );
  1403.             #endif
  1404.         }
  1405.  
  1406.         r.left += 11;
  1407.         r.right += 11;
  1408.                 
  1409.         digit = (workNumber + 1) / 10;            // Do 10's digit.
  1410.         digit = digit % 10L;
  1411.         if ((digit != 0) || (workNumber >= 100))
  1412.         {
  1413.             CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  1414.                     &((GrafPtr)workSrcMap)->portBits, 
  1415.                     &numbersSrc[digit], &r, srcCopy, 0L);
  1416.             #ifdef USE_INVALID_RECTS
  1417.             DSpContext_InvalBackBufferRect( gTheContext, &r );
  1418.             #endif
  1419.         }
  1420.         
  1421.         r.left += 11;
  1422.         r.right += 11;
  1423.  
  1424.         digit = (workNumber) % 10;            // Do 1's digit.
  1425.         CopyBits(&((GrafPtr)numberSrcMap)->portBits, 
  1426.                 &((GrafPtr)workSrcMap)->portBits, 
  1427.                 &numbersSrc[digit], &r, srcCopy, 0L);
  1428.         #ifdef USE_INVALID_RECTS
  1429.         DSpContext_InvalBackBufferRect( gTheContext, &r );
  1430.         #endif
  1431.     }
  1432. #endif
  1433. }
  1434.  
  1435. //--------------------------------------------------------------  DrawFrame
  1436.  
  1437. // This function is the "master" drawing function that calls all the above…
  1438. // routines.  It is called once per frame.
  1439.  
  1440. void DrawFrame (void)
  1441. {
  1442.     Boolean bannerInFront = false;
  1443.     
  1444.     {
  1445.         KeyMap theKeys;
  1446.         GetKeys(theKeys);
  1447.     
  1448.         if ((theKeys[1] & 0x004))
  1449.         {
  1450.             bannerInFront = true;
  1451.         }
  1452.     }
  1453.  
  1454.     if (!bannerInFront)
  1455.     {
  1456.         DrawBanner();
  1457.     }
  1458.  
  1459.     DrawTorches();                // Gee, draws the torches?
  1460.     
  1461.     DrawScoreFloaters();
  1462.     
  1463.     DrawHand();                    // Draws the hand?
  1464.     DrawEye();                    // A clue to easing your documentation demands…
  1465.     DrawPlayer();                // is to use "smart" names for your functions.
  1466.     CheckPlayerWrapAround();    // Check for player wrap-around.
  1467.     DrawEnemies();                // Handle all sphinx-type enemy drawing.
  1468.  
  1469.     DrawObelisks();            // draw the obelisks
  1470.     DrawPixelShatter();            // draw exploding pixels
  1471.     
  1472.     DrawLava();                    // add sparkling lava
  1473.  
  1474.     if (bannerInFront)
  1475.     {
  1476.         DrawBanner();
  1477.     }    
  1478.  
  1479. }
  1480.  
  1481. //--------------------------------------------------------------  GameQuitGraphics
  1482.  
  1483. void GameQuitGraphics(void)
  1484. {
  1485.     short h,v;
  1486.     
  1487.     for(v = 0; v < 480; v += 24)
  1488.     {
  1489.         for(h = 0; h < 640; h += 32)
  1490.         {
  1491.                 StartPixelShatter(h, v, 0, 0, kShatterLightningDust);
  1492.         }
  1493.     }
  1494.  
  1495.     CopyBits(    &((GrafPtr)origBackSrcMap)->portBits, 
  1496.                 &((GrafPtr)backSrcMap)->portBits, 
  1497.                 &backSrcRect, &backSrcRect, srcCopy, 0L);
  1498.     #ifdef USE_INVALID_RECTS
  1499.     DSpContext_InvalBackBufferRect( gTheContext, &backSrcRect );
  1500.     #endif
  1501. }
  1502.  
  1503. //--------------------------------------------------------------  GameIdleAnimation
  1504.  
  1505. void GameIdleAnimation(void)
  1506. {
  1507.     // do our idle animation
  1508.     DSpContext_GetBackBuffer( gTheContext, kDSpBufferKind_Normal, &workSrcMap );
  1509.     DumpBackToWorkMap();                    // clear the screen
  1510.     DrawBanner();
  1511.     DrawTorches();
  1512.     HandlePixelShatter();
  1513.     HandleLava();
  1514.     DrawLava();
  1515.     
  1516.     if (helpOpen)
  1517.     {
  1518.         CopyBits(&((GrafPtr)helpSrcMap)->portBits, 
  1519.             &((GrafPtr)workSrcMap)->portBits, 
  1520.             &helpSrc, &helpDest, srcCopy, 0L);
  1521.         #ifdef USE_INVALID_RECTS
  1522.         DSpContext_InvalBackBufferRect( gTheContext, &helpDest );
  1523.         #endif
  1524.     }
  1525.     
  1526.     DrawPixelShatter();
  1527.     HandleLightning();
  1528.  
  1529.     DSpContext_SwapBuffers( gTheContext, NULL, NULL );    
  1530. }
  1531.  
  1532.